//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#if _MSC_VER > 1000
#pragma once
#endif

#ifndef __CTHREAD_H__
#define __CTHREAD_H__

#include <elasys_server.h>
#include <linknode.h>
#include <interlocked.h>
#include "objenum.h"
#include "tlsmanager.h"

class CThread : public ObjectEnumeratorNode,
                public IThread,
                public IThreadContext
{
public:
    CARAPI_(IInterface *) GetObject() { return (IThread *)this; }

public:
    CARAPI_(PInterface) Probe(
        /* [in]  */ REIID riid);

    CARAPI_(UInt32) AddRef();

    CARAPI_(UInt32) Release();

    CARAPI Aggregate(
        /* [in] */ AggrType aggrType,
        /* [in] */ PInterface pObject);

    CARAPI GetDomain(
        /* [out] */ PInterface *ppObject);

    CARAPI Start();

    CARAPI Suspend();

    CARAPI Resume();

    CARAPI Join(
        /* [in] */ Millisecond32 timeOut,
        /* [out] */ WaitResult *pResult);

    CARAPI Interrupt();

    CARAPI Abort();

    CARAPI SetPriority(
        /* [in] */ ThreadPriority priority);

    CARAPI GetPriority(
        /* [out] */ ThreadPriority * pPriority);

    CARAPI GetId(
        /* [out] */ ThreadId * pTid);

    CARAPI SetName(
        /* [in] */ WString name);

    CARAPI GetName(
        /* [out] */ WStringBuf * pName);

    CARAPI GetState(
        /* [out] */ ThreadState * pState);

    CARAPI GetQuitCode(
        /* [out] */ QuitCode * pQuitCode);

    CARAPI GetStartTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetQuitTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetProcessorTimes(
        /* [out] */ Millisecond32 * pUserTime,
        /* [out] */ Millisecond32 * pPrivilegedTime);

    //IThreadContext
    CARAPI GetContext(
        /* [out] */ ArrayOf<Int32> *pContextArray);

    CARAPI SetContext(
        /* [out] */ const ArrayOf<Int32> &contextArray);

    CARAPI GetUserStackTop(
        /* [out] */ Address *pStackTop);

    CARAPI Quit();

public:
    static ECode New(
        /* [out] */ IThread ** ppThread);

    static ECode New(
        /* [in] */ Address entry,
        /* [in] */ Address userEntry,
        /* [in] */ Address userArgs,
        /* [in] */ ThreadCreationFlags flags,
        /* [out] */ IThread ** ppThread);

public:
    CThread();
    virtual ~CThread();

    ECode Constructor();
    ECode Constructor(
        /* [in] */ Address entry,
        /* [in] */ Address userEntry,
        /* [in] */ Address userArgs,
        /* [in] */ ThreadCreationFlags flags);

    void Helper_GetEntries(
        /* [out] */ Address * pElEntry,
        /* [out] */ Address * pUserEntry,
        /* [out] */ Address * pArgs);

    CTlsZone * Helper_GetTlsZone();

    void Helper_SetState(
        /* [in] */ ThreadState state);

    void Helper_QuitAsCurrent(
        /* [in] */ QuitCode quitCode);

private:
    PVoid    m_hThread;
    ThreadId m_threadId;

    Address  m_elEntry;
    Address  m_userEntry;
    Address  m_userArgs;
    CTlsZone * m_pTlsZone;

    ThreadState m_threadState;
    Interlocked m_nestedSuspend;
    PVoid       m_hLock;

    SystemTime  m_startTime;
    SystemTime  m_quitTime;
    QuitCode    m_quitCode;

private:
    Interlocked  m_Refs;
};

inline
CThread::CThread():m_hThread(NULL),
                m_threadId(-1),
                m_userEntry(0),
                m_userArgs(0),
                m_pTlsZone(NULL),
                m_threadState(ThreadState_Unstarted),
                m_hLock(NULL),
                m_quitCode(E_THREAD_ABORTED)
{}

inline
void CThread::Helper_GetEntries(
        /* [out] */ Address * pElEntry,
        /* [out] */ Address * pUserEntry,
        /* [out] */ Address * pUserArgs)
{
    assert(NULL != pElEntry);
    assert(NULL != pUserEntry);
    assert(NULL != pUserArgs);

    *pElEntry   = m_elEntry;
    *pUserEntry = m_userEntry;
    *pUserArgs  = m_userArgs;
}

inline
CTlsZone * CThread::Helper_GetTlsZone()
{
    assert(NULL != m_pTlsZone);
    return m_pTlsZone;
}

#endif // __CTHREAD_H__
